import gtk
import os
import re
import ConfigParser
   
class ParamConfig(ConfigParser.ConfigParser):
    def __init__(self):
        ConfigParser.ConfigParser.__init__(self)
        self.filename = 'config.ini'
        self.section = 'directory'
        self.viewdir = 'viewdir'
    
    def readParam(self):
        viewdir = ''
        try:
            self.read(self.filename)
            viewdir = self.get(self.section, self.viewdir)
        except ConfigParser.NoSectionError, e:
            pass
        except ConfigParser.NoOptionError, e:
            pass
        return viewdir

    def writeParam(self, viewdir):
        self.add_section(self.section)
        self.set(self.section, self.viewdir, viewdir)
        f = open(self.filename, 'w')
        self.write(f)
        f.close()

def extractProjs(sln_name):
    text = open(sln_name).read()

    pat = 'Project.*,\s*"(.+)",'
    repat = re.compile(pat)
    item = repat.findall(text)
    return item

def extractFiles(proj_name):
    text = open(proj_name).read()
    if proj_name.endswith('vcproj'):
        pat = '<File\s*RelativePath="(.*)"\s*>'
        repat = re.compile(pat)
        items = repat.findall(text)
    elif proj_name.endswith('csproj'):
        pat = '<Compile Include="(.*)">'
        repat = re.compile(pat)
        items = repat.findall(text)
    return items

def getSlns(fname):
    slns = []
    f = open(fname)
    for line in f:
        name = line.strip()
        if name != '':
            slns.append(name)
    return slns            

class MainWindow(gtk.Window):
    def __init__(self, parent=None):
        gtk.Window.__init__(self)
        
        self.set_title('Build Sln')
        #self.set_border_width(2)
        self.set_default_size(600, 480)
        self.set_position(gtk.WIN_POS_CENTER)
        self.connect("destroy", self.destroy)
        
        vbox = gtk.VBox(False, 0)
        menu = self.setupMenu()
        toolbar = self.get_toolbar()

        w = self.setupWidgets()
        vbox.pack_start(menu, False, False, 0)
        vbox.pack_start(toolbar, False, False, 0)
        vbox.pack_start(w, True, True, 0)
        
        self.statusbar = gtk.Statusbar()
        vbox.pack_end(self.statusbar, False, False, 0)

        self.add(vbox)
        self.show_all()

        config = ParamConfig()
        viewdir = config.readParam()
        self.input_entry.set_text(viewdir)
        
        buffer = self.text.get_buffer()
        self.find_tag = buffer.create_tag(foreground='red')
        self.now_tag = buffer.create_tag(foreground='red', background='green')
    
    def setupWidgets(self):
        vbox = gtk.VBox(False, 0)
        vbox.show()
        

        hbox = gtk.HBox()
        vbox.pack_start(hbox, False, False, 4)

        # label
        label = gtk.Label("View directory:")
        hbox.pack_start(label, False, False, 4)

        # entry
        e = gtk.Entry()
        #hbox.add(e)
        hbox.pack_start(e, True, True, 4)

        self.input_entry = e

        # button
        b = gtk.Button("Browse...")
        b.connect('clicked', self.OnSelectInput)
        hbox.pack_start(b, False, False, 4)

        button = gtk.Button('Refresh')
        hbox.pack_start(button, False, False, 4)
        button.connect('clicked', self.refresh)
        
        #
        hbox = gtk.HBox(False, 0)
        vbox.pack_start(hbox, False, False, 2)

        button = gtk.Button("Build")
        button.set_size_request(80, -1)
        button.set_border_width(2)
        hbox.pack_start(button, False, True, 5)

        cb = gtk.combo_box_new_text()
        hbox.pack_start(cb, False, False, 2)
        cb.append_text('Debug')
        cb.append_text('Release')
        cb.set_active(0)

        label = gtk.Label('Search')
        hbox.pack_start(label, False, False, 4)

        entry = gtk.Entry()
        hbox.pack_start(entry, False, False, 4)
        entry.connect('changed', self.search_text)

        button = gtk.Button('Select file')
        hbox.pack_start(button, False, False, 4)
        button.connect('clicked', self.get_file)
        
        button = gtk.Button('Prev')
        hbox.pack_start(button, False, False, 4)
        button.connect('clicked', self.move_prev)

        button = gtk.Button('Next')
        hbox.pack_start(button, False, False, 4)
        button.connect('clicked', self.move_next)

        hbox = gtk.HBox(False, 0)
        vbox.pack_start(hbox, True, True, 2)

        hpane = gtk.HPaned()
        hbox.pack_start(hpane, True, True, 2)
        #
        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
        sw.set_size_request(200, 200) 
        #hbox.pack_start(sw, True, True, 0)
        hpane.add1(sw)
        
        self.treestore = gtk.TreeStore(str)

        treeview = gtk.TreeView(self.treestore)
        sw.add(treeview)
        treeview.connect('row-activated', self.open_file)

        renderText = gtk.CellRendererText()
        column = gtk.TreeViewColumn('Solution Name', renderText, text=0)
        treeview.append_column(column)

        text = self.get_textview()
        #hbox.pack_start(text, True, True, 0)
        hpane.add2(text)

        return vbox
    
    def get_file(self, widget):
        f = gtk.FileChooserDialog(title='Select a file', 
                                  action=gtk.FILE_CHOOSER_ACTION_OPEN,
                                  buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        r = f.run()
        if r == gtk.RESPONSE_OK:
            filename = f.get_filename()
            print filename        
            buffer = self.text.get_buffer()
            buffer.set_text(open(filename).read())
 
        f.destroy()
    
    def move_prev(self, widget):
        self.now -= 1
        if self.now < 0:
            self.now = len(self.find_list) - 1
        self.scroll(self.now)            

    def move_next(self, widget):
        self.now += 1 
        if self.now > len(self.find_list) - 1:
            self.now = 0
        self.scroll(self.now)

    def search_text(self, widget, *data):
        text = widget.get_text() 
        buffer = self.text.get_buffer()
        start, end = buffer.get_bounds()
        buffer.remove_tag(self.find_tag, start, end)
        iter = buffer.get_iter_at_offset(0)
        find_list = []
        self.now = 0
        while True:
            res = iter.forward_search(text, gtk.TEXT_SEARCH_VISIBLE_ONLY|gtk.TEXT_SEARCH_TEXT_ONLY)
            if not res:
                break

            match_start, match_end = res
            find_list.append(res)
            buffer.apply_tag(self.find_tag, match_start, match_end)
            iter = match_end

        self.find_list = find_list
        self.scroll(0)
    
    def scroll(self, index):
        buffer = self.text.get_buffer()
        start, end = buffer.get_bounds()
        buffer.remove_tag(self.now_tag, start, end)
        if self.find_list and index in range(len(self.find_list)):
            start, end = self.find_list[index]
            buffer.apply_tag(self.now_tag, start, end)
            mark = buffer.create_mark(None, start, False)
            self.text.scroll_to_mark(mark, 0, True, 0.0, 1.0)
            buffer.delete_mark(mark)

    def get_textview(self):
        sw = gtk.ScrolledWindow()
        sw.set_shadow_type(gtk.SHADOW_ETCHED_IN)
        sw.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)

        text = gtk.TextView()
        sw.add(text)
        self.text = text

        return sw

    def open_file(self, treeview, path, column):
        if len(path) != 3:
            return

        model = treeview.get_model()

        it1 = model.get_iter(path)
        it2 = model.iter_parent(it1)
        it3 = model.iter_parent(it2)

        v1 = model.get_value(it1, 0)
        v2 = model.get_value(it2, 0)
        v3 = model.get_value(it3, 0)
        
        print v1
        print v2
        print v3

        head3, tail = os.path.split(v3)
        head2, tail = os.path.split(v2)
        head = os.path.join(head3, head2)
        path = os.path.join(head, v1)
        print path
        
        buffer = self.text.get_buffer()
        buffer.set_text(open(path).read())
        
        context_id = self.statusbar.get_context_id('st')
        self.statusbar.push(context_id, path)

    def setupMenu(self):
        menubar = gtk.MenuBar()
        menubar.show()
        
        agr = gtk.AccelGroup()
        self.add_accel_group(agr)

        # File
        filemenu = gtk.Menu()
        filemenu.show()
        
        openitem = gtk.ImageMenuItem(gtk.STOCK_OPEN, agr)
        key, mod = gtk.accelerator_parse('Ctrl+O')
        #openitem.add_accelerator('activate', agr, key, mod, gtk.ACCEL_VISIBLE)
        openitem.show()
        openitem.connect('activate', self.OnSelectInput)
        filemenu.append(openitem)
        
        sep = gtk.SeparatorMenuItem()
        filemenu.append(sep)

        exititem = gtk.ImageMenuItem(gtk.STOCK_QUIT, agr)
        key, mod = gtk.accelerator_parse('ctrl+Q')
        #exititem.add_accelerator('activate', agr, key, mod, gtk.ACCEL_VISIBLE)
        exititem.connect('activate', self.destroy)
        exititem.show()
        filemenu.append(exititem)

        fileitem = gtk.MenuItem('_File')
        fileitem.set_submenu(filemenu)
        fileitem.show()

        menubar.append(fileitem)

        # Help
        helpmenu = gtk.Menu()
        helpmenu.show()

        about = gtk.ImageMenuItem(gtk.STOCK_ABOUT, agr)
        about.connect('activate', self.about)
        helpmenu.append(about)
        about.show()

        helpitem = gtk.ImageMenuItem('_Help')
        helpitem.set_submenu(helpmenu)
        helpitem.show()
        
        menubar.append(helpitem)
        return menubar

    def about(self, widget, data=None):
        about = gtk.AboutDialog()
        about.set_program_name('Build Sln')
        about.set_version('0.9')
        about.set_copyright('(c) zliu')
        about.run()
        about.destroy()
            

    def destroy(self, widget, data=None):
        config = ParamConfig()
        config.writeParam(self.input_entry.get_text())
        gtk.main_quit()
    
    def OnSelectInput(self, data):
        f = gtk.FileChooserDialog(title='Choose a folder', action=gtk.FILE_CHOOSER_ACTION_SELECT_FOLDER, buttons=(gtk.STOCK_CANCEL, gtk.RESPONSE_CANCEL, gtk.STOCK_OPEN, gtk.RESPONSE_OK))
        r = f.run()
        if r == gtk.RESPONSE_OK:
            folder = f.get_current_folder()
            print folder
            self.input_entry.set_text(folder)
            self.fill_tree(folder)
        f.destroy()    

    def fill_tree(self, folder):
        self.treestore.clear()
        slns = getSlns('input.txt')
        for sln in slns:
            slnname = os.path.join(folder, sln)
            it = self.treestore.append(None, [slnname])
            projs = extractProjs(slnname)
            root, tail = os.path.split(slnname)
            for p in projs:
                it2 = self.treestore.append(it, [p])
                path = os.path.join(root, p)
                   
                try:
                    files = extractFiles(path)

                    if files:
                        for file in files:
                            self.treestore.append(it2, [file])
                except IOError, e:
                    print e
    
    def refresh(self, widget):
        self.fill_tree(self.input_entry.get_text())
    
    def get_toolbar(self):
        toolbar = gtk.Toolbar()
        toolbar.set_style(gtk.TOOLBAR_ICONS)

        open = gtk.ToolButton(gtk.STOCK_OPEN)
        quit = gtk.ToolButton(gtk.STOCK_QUIT)

        toolbar.insert(open, 0)
        toolbar.insert(quit, 1)
        return toolbar
        
def main():
    MainWindow()
    gtk.main()

if __name__ == '__main__':
    main()

